/*

 * Created on 2004-7-12

 *

 * Window - Preferences - Java - Code Style - Code Templates

 */

package com.stony.core.bo;

import java.sql.SQLException;
import java.util.Collections;

import org.apache.log4j.Logger;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.Transaction;
import org.hibernate.cfg.Configuration;
import org.hibernate.hql.classic.QueryTranslatorImpl;

import com.stony.core.dao.OracleExceptionConstants;
import com.stony.core.exception.RunException;

/**
 * @author stony.feng
 * 
 */
public abstract class HibernateBusinessObject extends JTXBusinessObject {

	/**
	 * 
	 * Comment for <code>SESSION</code>
	 * 
	 */

	public static final ThreadLocal SESSION = new ThreadLocal();

	public static final ThreadLocal EMPLOYEE = new ThreadLocal();

	/**
	 * 
	 * Comment for <code>logger</code>
	 * 
	 */

	private static Logger logger = Logger

	.getLogger(HibernateBusinessObject.class);

	/**
	 * 
	 * Comment for <code>sessionFactory</code>
	 * 
	 */

	private static SessionFactory sessionFactory;

	static {

		try {

			if (TRANSLOCAL) {

				sessionFactory = new Configuration().configure()

				.buildSessionFactory();

			} else {

				sessionFactory = new Configuration().configure()

				.buildSessionFactory();

			}

			if (logger.isDebugEnabled()) {

				logger.debug("Init SessionFactory");

			}

		} catch (Exception ex) {

			logger.error(ex);

		}

	}

	/**
	 * 
	 * @return the Session with ThreadLocal
	 * 
	 */

	final protected Session getSession() {

		return (Session) HibernateBusinessObject.SESSION.get();

	}

	/**
	 * 
	 * @see com.stony.core.bo.JTXBusinessObject#process()
	 * 
	 */

	final protected void process() {

		boolean flag = false;

		Session session = null;

		try {

			session = getSession();

			logger.debug("get Session" + session);

			Transaction trans = null;

			if (session == null) {

				if (logger.isDebugEnabled()) {

					logger.debug("Create Session");

				}

				session = sessionFactory.openSession();

				flag = true;

				SESSION.set(session);

				ROLL.set(null);

				if (logger.isDebugEnabled()) {

					logger.debug("Begin Transaction");

				}

				if (TRANSLOCAL) {

					trans = session.beginTransaction();

				}

			}

			try {

				performBusinessLogic();

				if (flag) {

					if (logger.isDebugEnabled()) {

						logger.debug("Commit Transaction Begin");

					}

					session.flush();

					if (TRANSLOCAL) {

						if (ROLL.get() == null) {

							trans.commit();

						} else {

							logger.error("Rollback Transaction By ROLL");
							trans.rollback();

						}

					}

					if (logger.isDebugEnabled()) {

						logger.debug("Commit Transaction End");

					}

				}

			} catch (Exception ex) {

				ex.printStackTrace();

				logger.error(ex);

				if (flag) {

					if (logger.isDebugEnabled()) {

						logger.debug("Rollback Transaction Begin");

					}

					if (TRANSLOCAL) {

						trans.rollback();

					}

					if (logger.isDebugEnabled()) {

						logger.debug("Rollback Transaction End");

					}

				}

				if (ex instanceof RunException) {

					throw (RunException) ex;

				}

				throw new RunException(ex);

			}

		} catch (Exception ex) {

			logger.error(ex);

			if (ex instanceof RunException) {

				throw (RunException) ex;

			}

			throw new RunException(ex);

		} finally {

			if (flag) {

				SESSION.set(null);

				ROLL.set(null);

				try {

					if (logger.isDebugEnabled()) {

						logger.debug("Close Session");

					}

					session.close();

				} catch (Exception ex) {

					logger.error(ex);

				}

			}

		}

	}

	protected void handleSQLException(SQLException he) {

		logger.error(he);

		RunException ex = null;

		switch (he.getErrorCode()) {

		case OracleExceptionConstants.UNIQUE_CONSTRAINTS:

			he.printStackTrace();
			ex = new RunException("error.oracle.unique");

			break;

		case OracleExceptionConstants.NOT_NULL_CONSTRAINTS:

			ex = new RunException(he);

			break;

		case OracleExceptionConstants.INTEGRITY_CONSTRAINTS_PARENT:

			ex = new RunException(he);

			break;

		case OracleExceptionConstants.INTEGRITY_CONSTRAINTS_CHILD:

			ex = new RunException(he);

			break;

		case OracleExceptionConstants.TOO_LARGE:

			ex = new RunException(he);

			break;

		case OracleExceptionConstants.APPLICATION_CONSTRAINTS:

			String message = he.getMessage();
			int pos1 = message.indexOf('[');
			int pos2 = message.indexOf(']');
			int pos3 = message.indexOf('(');
			int pos4 = message.indexOf(')');

			System.out.println(message);
			if (pos1 > 0 && pos2 > 0) {
				if (pos3 > 0 && pos4 > 0)
					ex = new RunException(message.substring(pos1 + 1, pos2),
							new String[] { message.substring(pos3 + 1, pos4) });
				else
					ex = new RunException(message.substring(pos1 + 1, pos2));
			} else
				ex = new RunException(he.getMessage());

			break;

		default:

			ex = new RunException(he);

		}

		throw ex;

	}

	protected String getSQLString(String originalHql) throws Exception {

		QueryTranslatorImpl queryTranslator = new QueryTranslatorImpl(
				originalHql, originalHql, Collections.EMPTY_MAP,
				(org.hibernate.engine.SessionFactoryImplementor) sessionFactory);

		queryTranslator.compile(Collections.EMPTY_MAP, false);

		return queryTranslator.getSQLString();
	}

	/**
	 * 
	 */
	abstract protected void performBusinessLogic();

}